﻿using BarManager.Core.ApplicationService.Interfaces;
using BarManager.Core.BusinessRules.Interfaces.Validator;
using BarManager.Core.Common;
using BarManager.Core.DomainModel;
using BarManager.Core.DomainService;
using BarManager.Core.Entity;
using System.Collections.Generic;

namespace BarManager.Core.ApplicationService
{
    public class ProductoService : BaseApplicationService<Producto>, IProductoService
    {
        private IProductoRepository Repository
        { get { return (IProductoRepository)this.BaseRepository; } }

        private IMailer Mailer { get; set; }

        public ProductoService(IObjectContext context, IProductoRepository repository, IProductoValidator validator)
            : base(context, repository, validator)
        {
            // Mailer = mailer;          
        }

        //- Actualiza producto y puede enviar alarmas
        public void Update(Producto producto, bool sendStockAlarm)
        {
            Repository.Update(producto);

            //- Envia alarma de stock
            if (producto.ControlarStock && sendStockAlarm && producto.StockMinimo <= producto.Stock)
            {
                if (producto.Stock == 0)
                    Mailer.Send("Producto Sin Stock",
                        string.Format("El producto Id:{0} - {1} No tiene stock.", producto.Id, producto.Nombre));
                else
                    Mailer.Send("Producto con Stock Minimo",
                            string.Format("El producto Id:{0} - {1} tiene un stock de Items: {2}.", producto.Id, producto.Nombre, producto.Stock));
            }
        }

        //- Productos que pertenezcan a una cat y q tengan sotck o que sean de elaboracion en cocina
        public IEnumerable<Producto> GetAllProductosByCategoria(int idCategoria)
        {
            return base.Find(x => x.CategoriaId == idCategoria && (x.Stock > 0 || x.Categoria.ElaboracionPropia));
        }

        #region Stock en Ordenes
        public void Stock(IEnumerable<OrdenDetalleBase> productos, MovimientoStock movimiento)
        {
            foreach (var item in productos) this.Stock(item, item.Cantidad, movimiento);
        }

        public void Stock(OrdenDetalleBase item, int cantidad, MovimientoStock movimiento)
        {
            //- Detalle Promocion
            if (item is OrdenDetallePromocion)
                foreach (var promo in (item as OrdenDetallePromocion).Promocion.PromocionDetalleList)
                    StockProducto(promo.Producto, promo.Cantidad * cantidad, movimiento);

            //- Detalle Producto
            if (item is OrdenDetalleProducto)
                StockProducto((item as OrdenDetalleProducto).Producto, cantidad, movimiento);
        }
        #endregion

        #region Stock en Envios
        public void Stock(IEnumerable<EnvioDetalleBase> productos, MovimientoStock movimiento)
        {
            foreach (var item in productos) this.Stock(item, item.Cantidad, movimiento);
        }

        public void Stock(EnvioDetalleBase item, int cantidad, MovimientoStock movimiento)
        {
            //- Detalle Promocion
            if (item is EnvioDetallePromocion)
                foreach (var promo in (item as EnvioDetallePromocion).Promocion.PromocionDetalleList)
                    StockProducto(promo.Producto, promo.Cantidad * cantidad, movimiento);

            //- Detalle Producto
            if (item is EnvioDetalleProducto)
                StockProducto((item as EnvioDetalleProducto).Producto, cantidad, movimiento);
        }
        #endregion

        #region Metodos comunes
        private bool StockProducto(Producto producto, int cantidad, MovimientoStock movimiento)
        {
            if (producto.ControlarStock)
            {
                //- Buscamos el producto a modificar stock
                Producto productoUpdate = base.Get(x => x.Id == producto.Id);
                
                //- Repone stock
                if (movimiento == MovimientoStock.Agregar)
                {
                    if (cantidad > 0)
                    {
                        productoUpdate.Stock += cantidad;
                        //this.Update(productoUpdate, false);
                        return true;
                    }
                }

                //- Descuenta stock
                if (movimiento == MovimientoStock.Descontar)
                {
                    if (productoUpdate.Stock >= cantidad)
                    {
                        productoUpdate.Stock -= cantidad;
                        //this.Update(productoUpdate, false);
                        return true;
                    }
                }
                return false;
            }
            return true;
        }
        #endregion
    }
}
